package com.globefrog.framework.web.interceptor;

import com.globefrog.framework.common.annontation.RequestTrace;
import com.globefrog.framework.common.constant.CommonConstants;
import com.globefrog.framework.log.ActionLog;
import com.globefrog.framework.log.ActionLogImpl;
import com.globefrog.framework.web.wrapper.HttpRequestWrapper;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * 请求体拦截器.
 * HttpRequest—>DispactherServlet—>HandlerInterceptor->Controller—>HandlerInterceptor->HttpResponse
 *
 * @author : caijinbang
 * @date : Create in 2021-01-14
 */
public class RequestBodyInterceptor extends HandlerInterceptorAdapter {

  private static final String LOG_PARAM = "body";

  public RequestBodyInterceptor() {
  }

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
      Object handler) throws IOException {
    if (handler instanceof HandlerMethod) {
      HandlerMethod handlerMethod = (HandlerMethod) handler;
      RequestTrace logBody = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), RequestTrace.class);
      RequestMapping requestMapping = AnnotationUtils.findAnnotation(
          handlerMethod.getMethod(), RequestMapping.class
      );
      HttpRequestWrapper requestWrapper;
      if (request instanceof HttpRequestWrapper && logBody != null && needLog(requestMapping)) {
        requestWrapper = (HttpRequestWrapper) request;
        logRequest(requestWrapper);
      }
    }
    return true;
  }

  /**
   * 是否需要打印日志的请求.
   *
   * @param requestMapping 请求映射
   * @return 是否需要打印日志的请求
   */
  private boolean needLog(RequestMapping requestMapping) {
    if (requestMapping == null) {
      return false;
    } else {
      List<RequestMethod> methods = Arrays.asList(requestMapping.method());
      return methods.contains(RequestMethod.POST) || methods.contains(RequestMethod.PUT);
    }
  }

  private void logRequest(HttpRequestWrapper requestWrapper) {
    String body = requestWrapper.getBody();
    ActionLogImpl actionLogImpl = ActionLogImpl.getInstance();
    if (actionLogImpl != null) {
      if (StringUtils.hasText(body)) {
        body = body.replaceAll(CommonConstants.NEW_LINE, CommonConstants.SPACE)
            .replaceAll(CommonConstants.RETURN, CommonConstants.SPACE)
            .replaceAll(CommonConstants.TAB, CommonConstants.SPACE);
        actionLogImpl.logContext(LOG_PARAM, body);
      } else {
        ActionLog actionLog = actionLogImpl.currentActionLog();
        actionLog.setHttpStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
      }
    }
  }
}
